<template>
  <div class="menu-tree">
    <el-tree :data="data" node-key="id" default-expand-all draggable :expand-on-click-node="expandClick" :allow-drag="treeAllowDrag" :allow-drop="treeAllowDrop" @node-contextmenu="handleContextmenu" @node-click="handlerClick">
      <span slot-scope="{ node, data }">
        <span>{{ node.label }}</span>
        <i v-if="!data.root" :class="`tree-icon el-icon-${data.status || 'success'} ${data.status}`"></i>
      </span>
    </el-tree>
    <el-cascader-panel ref="panel" :options="options" @change="change" v-if="contextmenuFlag" class="menu-right" :style="{ left: contentmenuX + 'px', top: contentmenuY + 'px' }" />
  </div>
</template>

<script>
import _cloneDeep from 'lodash/cloneDeep'
let id = 1000
export default {
  name: 'MenuTree',
  props: {
    data: {
      type: Array,
      default() {
        return []
      }
    },
    getAddList: {
      type: Function,
      default() {
        return []
      }
    },
    onlyChild: {
      type: Boolean,
      default: false,
    },
    allowDrag: {
      type: Function,
      default() {
        return true
      }
    },
    allowDrop: {
      type: Function,
      default() {
        return true
      }
    },
    expandClick: {
      type: Boolean,
      default: true,
    }
  },
  data() {
    return {
      contentmenuX: '',
      contentmenuY: '',
      contextmenuFlag: false,
      selectVal: [],
      clipData: null,
      treeData: [],
      selectData: {},
      selectNode: null,
      addList: []
    }
  },
  computed: {
    options() {
      return [
        {
          value: 'add',
          label: '新增节点',
          children: this.addList
        },
        {
          value: 'del',
          label: '删除节点'
        },
        {
          value: 'copy',
          label: '复制节点'
        },
        {
          value: 'shear',
          label: '剪切节点'
        },
        {
          value: 'paste',
          label: '粘贴节点'
        }
      ]
    }
  },
  watch: {
    contextmenuFlag() {
      window.addEventListener('mousedown', this.watchContextmenu)
    }
  },
  methods: {
    watchContextmenu() {
      const panel = this.$refs.panel
      // 当不是点击menu框时，把menu框关闭
      if ((panel && !panel.$el.contains(event.target)) || event.button !== 0) {
        this.contextmenuFlag = false
        window.removeEventListener('mousedown', this.watchContextmenu)
      }
    },
    // 右键弹出菜单
    handleContextmenu(event, data, node) {
      if (data.root) return;
      // 先获取到该节点可新增的节点
      this.addList = this.getAddList(data, node)

      this.selectData = data
      this.selectNode = node
      event.preventDefault()
      event.stopPropagation()
      this.contentmenuX = event.clientX
      this.contentmenuY = event.clientY
      this.contextmenuFlag = true
    },

    // 选择对节点的操作
    change(selectVal) {
      this.contextmenuFlag = false
      this.selectVal = selectVal
      const type = selectVal[0]
      try {
        this[`${type}Event`]()
      } catch (err) {
        this.$message.error('请选择正确的节点')
      }
    },
    // 增加节点
    addEvent(childData) {
      const addList = this.addList
      if (!childData && (!addList || !addList.length)) {
        this.$message.error('无新增节点类型')
        return
      }
      const newChild = _cloneDeep(Object.assign({}, childData || addList.find(d => d.value === this.selectVal[1]), { id: id++, status: 'warning' }))
      const data = this.selectData

      //只允许插入一个子节点
      // if (data.onlyChild && data.children && data.children.length >= 1) {
      //   this.$message.error('只能添加一个字段')
      //   return false
      // }
      if (this.onlyChild && data.children && data.children.length >= 1) {
        this.$message.error('只能添加一个字段')
        return false
      }

      //如果添加的节点含有子节点（报文配置的报文分支）
      if (newChild.child && newChild.child.length){
        newChild.children = newChild.child
      }
      // 插入为子节点
      if (this.selectData.dropInner) {
        if (!data.children) {
          this.$set(data, 'children', [])
        }
        data.children.push(newChild)
      } else {
        // 向后插入节点
        const parent = this.selectNode.parent
        const children = parent.data.children || parent.data
        children.push(newChild)
      }
      this.$message.success('添加节点成功')
    },
    // 删除节点
    delEvent() {
      return this.$confirm('确定要删除该节点么?', '温馨提示', {
        type: 'warning'
      }).then(() => {
        const data = this.selectData
        const parent = this.selectNode.parent
        const children = parent.data.children || parent.data
        children.splice(children.findIndex(d => d.id === data.id), 1)
      })
    },
    // 复制节点
    copyEvent() {
      this.clipData = this.selectData
      this.$message.success('已复制该节点')
    },
    // 剪切节点
    shearEvent() {
      this.delEvent().then(() => {
        this.clip = null
        this.copyEvent()
      })
    },
    // 粘贴节点
    pasteEvent() {
      if (!this.clipData) {
        this.$message.error('请先复制您需要粘贴的节点！')
        return
      }
      this.addEvent(this.clipData)
      this.clipData = null
    },

    // 允许拖拽的方法
    treeAllowDrag(node) {
      // 以调用组件传入的允许拖拽的方法为准
      return this.allowDrag(node)
    },
    // 允许放置的方法
    treeAllowDrop(draggingNode, dropNode, type) {
      // 若该节点禁止其它节点放置为他的子节点
      if (!dropNode.data.dropInner) {
        // 则不允许放置
        return type !== 'inner'
      }
      // 若该节点无禁止放置的类型，则以调用组件传入的允许放置的方法为准
      return this.allowDrop(draggingNode, dropNode, type)
    },
    handlerClick (data,node) {
      this.$emit('handlerClick', data,node)
    }
  }
}
</script>

<style lang="scss">
@import '~@/styles/variables.scss';
.menu-tree {
  .menu-right {
    position: fixed;
    background-color: #ffffff;
    z-index: 1;
  }
}

.tree-icon {
  margin-left: 6px;
  &.success {
    color: $success-color;
  }
  &.warning {
    color: $warning-color;
  }
  &.error {
    color: $danger-color;
  }
}
</style>
